﻿using System;
using System.Data;
using System.Data.Common;
using System.Configuration;
using System.Data.SqlClient;

namespace DuLabs.Classic.Util
{
    public sealed class Database
    {
        public string ConnectionString { get; private set; }
        public DbProviderFactory DbProviderFactory { get; private set; }

        private Database()
        { 
        
        }

        public static Database CreateDatabase(string settingsName)
        {
            if (string.IsNullOrWhiteSpace(settingsName))
            {
                throw new ArgumentNullException("settingsName");
            }

            ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings[settingsName];

            if (settings == null)
            {
                throw new NullReferenceException("无法根据指定的名称获取数据库连接字符串的配置项");
            }

            try
            {
                return Database.CreateDatabase(settings.ConnectionString, settings.ProviderName);
            }
            catch
            {
                throw;
            }
        }

        public static Database CreateDatabase(string connectionString, string providerName)
        {
            try
            {
                Database database = new Database();
                database.DbProviderFactory = DbProviderFactories.GetFactory(providerName);                
                database.ConnectionString = connectionString;
                return database;
            }
            catch
            {
                throw;
            }
        }

        public DbConnection CreateConnection()
        {
            try
            {
                DbConnection dbConnection = this.DbProviderFactory.CreateConnection();
                dbConnection.ConnectionString = this.ConnectionString;
                return dbConnection;
            }
            catch
            {
                throw;
            }
        }

        public DbCommand CreateCommand(CommandType commandType, string commandText, params DbParameter[] parameters)
        {
            try
            {
                DbConnection dbConnection = this.CreateConnection();
                DbCommand dbCommand = dbConnection.CreateCommand();
                dbCommand.CommandType = CommandType.Text;
                dbCommand.CommandText = commandText;
                
                foreach (DbParameter param in parameters)
                {
                    dbCommand.Parameters.Add(param);
                }

                return dbCommand;
            }
            catch
            {
                throw;
            }
        }

        public int ExecuteNonQuery(DbCommand dbCommand, DbTransaction dbTransaction)
        {
            if (dbCommand == null)
            {
                throw new ArgumentNullException("dbCommand");
            }            

            if (dbTransaction != null)
            {
                dbCommand.Connection = dbTransaction.Connection;
                dbCommand.Transaction = dbTransaction;
            }

            if (dbCommand.Connection == null)
            {
                throw new NullReferenceException("dbCommand.Connection");
            }

            try
            {
                if (dbCommand.Connection.State != ConnectionState.Open)
                {
                    dbCommand.Connection.Open();
                }

                return dbCommand.ExecuteNonQuery();
            }
            catch
            {
                throw;
            }
            finally
            {
                if (dbCommand.Connection.State != ConnectionState.Closed)
                {
                    dbCommand.Connection.Close();
                }
            }
        }

        public int ExecuteNonQuery(DbCommand dbCommand)
        {
            try
            {
                return this.ExecuteNonQuery(dbCommand);
            }
            catch
            {
                throw;
            }
        }

        public int ExecuteNonQuery(CommandType commandType, string commandText)
        {
            try
            {
                DbCommand dbCommand = this.CreateCommand(commandType, commandText, null);
                return this.ExecuteNonQuery(dbCommand);
            }
            catch
            {
                throw;
            }
        }
    }
}
